package com.icehelper.hades.base.log;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;

/**
 * @author Leon Sun
 */
public class HadesLogger extends ExtendedLoggerWrapper {

  private final ExtendedLoggerWrapper logger;

  /**
   * Constructor that wraps and existing Logger.
   *
   * @param logger         The Logger to wrap.
   * @param name           The name of the Logger.
   * @param messageFactory TODO
   */
  public HadesLogger(ExtendedLogger logger,
      String name, MessageFactory messageFactory) {
    super(logger, name, messageFactory);
    this.logger = this;
  }

  /**
   * 创建当前类的logger
   * @return
   */
  public static HadesLogger create(){
    Throwable t = new Throwable();
    StackTraceElement stackTraceElement = t.getStackTrace()[1];
    return create(stackTraceElement.getClass());

  }

  /**
   * 根据Class类型创建logger
   * @param clazz
   * @return
   */
  public static HadesLogger create(Class<?> clazz){
    Logger logger = LogManager.getLogger(clazz);
    return new HadesLogger((ExtendedLogger) logger,logger.getName(),logger.getMessageFactory());
  }

  /**
   * 根据类名创建logger
   * @param clazzName
   * @return
   */
  public static HadesLogger create(String clazzName){
    Logger logger = LogManager.getLogger(clazzName);
    return new HadesLogger((ExtendedLogger) logger,logger.getName(),logger.getMessageFactory());
  }

  public void dlDebug(String dlTag,String msg,Object ...args){
    HadesLogEventFactory.setKv(LogConstant.KEY_DL_TAG, dlTag);
    logger.logIfEnabled( HadesLogger.class.getName(), Level.DEBUG,null, msg, args);
  }

  public void dlInfo(String dlTag, String msg, Object ... args){
    HadesLogEventFactory.setKv(LogConstant.KEY_DL_TAG, dlTag);
    logger.logIfEnabled( HadesLogger.class.getName(), Level.INFO,null, msg, args);
  }

  public void dlWarn(String dlTag, String msg, Object ... args){
    HadesLogEventFactory.setKv(LogConstant.KEY_DL_TAG, dlTag);
    logger.logIfEnabled( HadesLogger.class.getName(), Level.WARN,null, msg, args);
  }

  public void dlError(String dlTag, String msg, Throwable t){
    HadesLogEventFactory.setKv(LogConstant.KEY_DL_TAG, dlTag);
    logger.logIfEnabled( HadesLogger.class.getName(), Level.ERROR,null, msg, t);
  }

  public void dlFatal(String dlTag, String msg, Throwable t){
    HadesLogEventFactory.setKv(LogConstant.KEY_DL_TAG, dlTag);
    logger.logIfEnabled( HadesLogger.class.getName(), Level.FATAL,null, msg, t);
  }

  public LogKvBuilder addKv(String key, Object value) {
    return new LogKvBuilder(key, value, this);
  }

  public HadesLogger addKvs(Map<String, ?> kvs) {
    if (!kvs.isEmpty()) {
      Map<String, String> map = new HashMap<>(kvs.size());
      kvs.forEach((k, v) -> map.put(k, v == null ? "" : String.valueOf(v)));
      fillKvs(map);
    }
    return this;
  }

  private static void fillKvs(Map<String, String> kvs) {
    if (!kvs.isEmpty()) {
      kvs.forEach( HadesLogEventFactory::setKv);
    }
  }

  public static class LogKvBuilder {

    private HadesLogger logger;
    private Map<String, String> kvs = new HashMap<>();

    private LogKvBuilder(String key, Object value, HadesLogger log) {
      super();
      kvs.put(key, Objects.toString(value));
      this.logger = log;
    }

    public LogKvBuilder addKv(String key, Object value) {
      kvs.put(key, Objects.toString(value));
      return this;
    }

    public HadesLogger logger() {
      fillKvs(kvs);
      return logger;
    }
  }
}
